#include "gtest/gtest.h"
#include <memory>

#include "helper/unittest/Tracer.h"
#include "helper/unittest/TestObjects.h"


//TODO: output stream style support  2023-05-25
/* TODO:
EXPECT.assign({
  c"construtor",
  m"method",
  o"tmp_dir/sub_dir",
  o"tmp_dir/sub_dir/grand_dir",
  d"destructor",
});


TracerComparator()
.lclear()
.lassign("xxxx").lassign({"xxxx", "yyyy"})
.lappend("xxxxx").lappend({"xxxx", "yyy"})
.lcall( std::functional<void(Tracer & left)>  ).lcall( std::functional<Tracer(Tracer & left)> )

.rclear()
.rassgin("xxxx").rassign({"xxxx", "yyyy"})
.rappend("xxxx").lappend({"xxxx", "yyyy"})
.rcall( std::functional<void (Tracer & right)> ).lcall( std::functional<Tracer(Tracer & right)> )

.result();

.assert(function<void ()>)

TracerComparator()
  //std::functional<void(Tracer & tracer)>;
  .left([&top_dir](auto & tracer){
    for(auto & p: fs::recursive_directory_iterator(top_dir)){
      tracer.operation(p.path().native());
    }
  })
  //std::functional<Tracer ()>  { tracer = "new....";}
  .leftAssign()
  //std::functional<Tracer & (Tracer & tracer)>
  .leftAppend()
  .right(o"tmp_dir")
  .right(o"tmp_dir")
  .right({
    o"tmp_dir",
    o"tmp_dir/sub_dir",
  })
  .eq(
    Exepct.reset()
    .op("tmp_dir/sub_dir")
    .op("tmp_dir/sub_dir/grand_dir")
  )
  .eq({
    o"tmp_dir/sub_dir",
    o"tmp_dir/sub_dir/grand_dir",
  })
  ;*/



using namespace helper;
using namespace unittest;

TEST(TracerTest, testGlobalUse){
    TRACER.reset();
    EXPECT.reset();
    ASSERT_EQ(EXPECT, TRACER);

    EXPECT.ctor();
    TRACER.ctor();
    ASSERT_EQ(EXPECT, TRACER);

    EXPECT.dtor();
    TRACER.dtor();
    ASSERT_EQ(EXPECT, TRACER);
}

TEST(TracerTest, testObjectAsMember){
    EXPECT.reset().ctor().method("set").methodConst("get");

	ObjectAsMember obj;  
    obj.set().get();
    ASSERT_EQ(EXPECT, obj.getTracer());
}

TEST(TracerTest, testObjectAsRef){
    EXPECT.reset().ctor().method("set").method("get").dtor();

	{
		ObjectAsRef obj(TRACER.reset()); 
        obj.set().get();
	}
    ASSERT_EQ(EXPECT, TRACER);
}

TEST(TracerTest, testObjectAsBase){
    EXPECT.reset().ctor().method("set").methodConst("get");

	ObjectAsBase obj;
	obj.set().get();
    ASSERT_EQ(EXPECT, obj.ref());
}


TEST(TracerTest, testTracerWithInitString){
    {
        Tracer t1("id");
        Tracer t2("id2");
        ASSERT_NE(t1, t2);
    }
    {
        Tracer t1("id1");
        ObjectAsRef obj(t1);

        Tracer t2("id2");
        ObjectAsRef obj2(t2); 

        ASSERT_NE(t1, t2);
    }
}

TEST(TracerTest, testPair){
  Tracer t("pairtest");
    t.pair("key", 1)
    .pair("key", 1u)
    .pair("key", 1l)
    .pair("key", 1lu)
    .pair("key", 1ll)
    .pair("key", 1ull)
    .pair("key", float(1.0))
    .pair("key", double(1.0))
    .pair("key", (long double)1.0)
    .pair("key", "value")
    .pair("key", std::string("value"))
    ;
    ASSERT_EQ("pairtest:key-1:key-1:key-1:key-1:key-1:key-1:key-1.000000:key-1.000000:key-1.000000:key-value:key-value", t.toString());
}

TEST(TracerTest, unequalPrintout){
  EXPECT.reset().ctor();
  TRACER.reset().dtor();
  ASSERT_NE(EXPECT, TRACER); // if ASSERT_EQ(EXPECT, TRACER); print out the  std::cout << expect-object && tracer-obj;
}
